package net.goodapp.util;

import java.io.File;
import java.io.IOException;
import java.sql.SQLException;

import javax.sql.DataSource;

import org.apache.commons.dbcp.BasicDataSourceFactory;
import org.apache.commons.io.FileUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.io.StringWriter;
import java.nio.charset.Charset;
import java.util.Properties;
import java.util.ArrayList;
import java.util.List;

import org.apache.velocity.app.Velocity;
import org.apache.velocity.app.VelocityEngine;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;

import net.goodapp.MainClass;
import net.goodapp.dao.DatabaseDAO;
import net.goodapp.model.ColumnInfo;
import net.goodapp.model.TableInfo;
import net.goodapp.service.DatabaseService;

public class XMLGenerator {
	private static final Log logger = LogFactory.getLog(XMLGenerator.class);
	private static final Charset charset=Charset.forName(MainClass.UTF8ENCODING);
	
	private XMLGenerator(){}
	/**
	 * 生成xml中间文件，可以基于中间文件的基础上修改后生成POJO/DAO/Service文件
	 */
	public static void generateConfigurationXML(){
		Properties dbcpProperties = new Properties();
		
		DataSource dataSource=null;
		List<TableInfo> tableInfos=null;
		DatabaseService service=null;
		try {
			// 配置文件和当前类的class放在一起
			dbcpProperties.load(XMLGenerator.class.getResourceAsStream("/dbcp.properties"));
		} catch (IOException e) {
			logger.error(e.getMessage());
		}
        try {
			dataSource = BasicDataSourceFactory.createDataSource(dbcpProperties);
			DatabaseDAO dao=new DatabaseDAO();
	        dao.setDataSource(dataSource);
			service=new DatabaseService();
			service.setDatabaseDAO(dao);
		} catch (Exception e) {
			logger.error(e.getMessage());
		}
        
		
		try {
			tableInfos=service.getTableInfos();
		} catch (SQLException e) {
			logger.error(e.getMessage());
		}catch (IOException ioException) {
			logger.error(ioException.getMessage());
		}
		
		if(tableInfos==null||tableInfos.size()==0){
			logger.error("Application will stop because of no data.");
			return;
		}
		
		Properties velocityProperties = new Properties();  
		velocityProperties.put("file.resource.loader.class",  
		"org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader"); 
		//设置velocity的输入输出为utf-8编码，以防出现乱码
		velocityProperties.put(Velocity.ENCODING_DEFAULT, MainClass.UTF8ENCODING);
		velocityProperties.put(Velocity.INPUT_ENCODING, MainClass.UTF8ENCODING);
		velocityProperties.put(Velocity.OUTPUT_ENCODING, MainClass.UTF8ENCODING); 
		
		//初始化并取得Velocity引擎
		VelocityEngine velocityEngine = new VelocityEngine();
		velocityEngine.init(velocityProperties);
		//取得velocity的模版
		Template template = velocityEngine.getTemplate("databaseConfig.vm");
		//取得velocity的上下文context
		VelocityContext context = new VelocityContext();
		logger.info("put "+tableInfos.size()+" tables in context");
		
		context.put("nc", NamingConventions.class);
		//把数据填入上下文
		context.put("tableInfos", tableInfos);
		
		//输出流
		StringWriter writer = new StringWriter();
		//转换输出
		template.merge(context, writer);
		File file=null;
		try {
			file=new File("javaDatabaseconfig.xml");
			FileUtils.writeStringToFile(file, writer.toString(), charset, false);
		}catch (IOException e) {
			logger.error(e.getMessage());
		}
		//System.out.println(writer.toString());
	}
	
	/**
	 * 读取中间配置文件中的配置信息
	 * @param path 中间配置文件的路径
	 * @return 返回包含中间配置文件中的配置信息的数据表示
	 * @throws DocumentException 
	 */
	@SuppressWarnings("unchecked")
	public static List<TableInfo> readConfigurationXML(String path){
		List<TableInfo> tableInfos=null;
		
		SAXReader reader = new SAXReader(); 
		Document document=null;
		try {
			document = reader.read(new File("javaDatabaseconfig.xml"));
		} catch (DocumentException e) {
			logger.error(e.getMessage());
		} 
		Element tableNodes = document.getRootElement();
		
		List<Element> tableNodeList=tableNodes.elements("Table");
		TableInfo tableInfo=null;
		ColumnInfo columnInfo=null;
		List<Element> columnNodeList=null;
		tableInfos=new ArrayList<TableInfo>(tableNodeList.size());
		for (Element tableNode : tableNodeList) {
			tableInfo=new TableInfo();
			tableInfo.setEntityName(tableNode.attributeValue("EntityName"));
			tableInfo.setPrimaryKeyName(tableNode.attributeValue("PrimaryKeyName"));
			tableInfo.setPrimaryKeyType(tableNode.attributeValue("PrimaryKeyType"));
			tableInfo.setPrimaryKeyColumnName(tableNode.attributeValue("PrimaryKeyColumnName"));
			tableInfo.setRemarks(tableNode.attributeValue("Remarks"));
			tableInfo.setTableName(tableNode.attributeValue("TableName"));
			
			columnNodeList=tableNode.elements("Column");
			for (Element columnNode : columnNodeList) {
				columnInfo=new ColumnInfo();
				columnInfo.setColumnName(columnNode.attributeValue("ColumnName"));
				columnInfo.setJavaType(columnNode.attributeValue("JdbcType"));
				columnInfo.setMaxLength(Integer.parseInt(columnNode.attributeValue("MaxLength")));
				columnInfo.setNullable(Boolean.parseBoolean(columnNode.attributeValue("Nullable")));
				//columnInfo.setOrdinal(columnNode.attributeValue("Ordinal"));
				columnInfo.setPropertyName(columnNode.attributeValue("PropertyName"));
				columnInfo.setRemarks(columnNode.attributeValue("Remarks"));
				columnInfo.setTypeName(columnNode.attributeValue("TypeName"));
				tableInfo.getColumnInfos().add(columnInfo);
			}
			tableInfos.add(tableInfo);
			logger.info("Load table configuration with name "+tableInfo.getTableName()+".");
		}
		return tableInfos;
	}
}
